#include "StdAfx.h"
#include "mpegts.h"
#include "log.h"
#include "TSG.h"
#include "TreeNode.h"

#define MAX_PSI_PID			500
#define MAX_SECTION_LEN		4096

struct AssemblingSectionNode
{
	CAssemblingSection* pSection;
	AssemblingSectionNode* pNext;
};

extern CLogFile theLogFile;
static int AFX_CDECL LOG(LOG_LEVEL level, const wchar_t* lpszFormat, ...)
{
	va_list args;
	int nCount;
	wchar_t szText[512] = {0};

	va_start(args, lpszFormat);
	nCount = vswprintf_s(szText, sizeof(szText)/2, lpszFormat, args);
	va_end(args);
	
	szText[nCount] = 0x0D;
	szText[nCount+1] = 0x0A;
	szText[nCount+2] = 0;
	CLog Log(_T("[TS]"), 5, level, szText, lstrlen(szText));

	CLogNode* pLogNode = new CLogNode(Log);
	ASSERT(pLogNode);
	if(pLogNode)
	{
		theLogFile.AddLogNode(pLogNode);
	}

	return 0;
}

static void PSIInit(void);
static SHORT PSI_PID[MAX_PSI_PID];
static SHORT PSI_PID_count = 0;
static AssemblingSectionNode* pHead = NULL;

static BOOL GetBit(BYTE data, BYTE index);
static CAssemblingSection* FindAssemblingSection(CTSP* pTSP);
static BOOL InsertNewAssemblingSection(CAssemblingSection* pSection);
static BOOL DeleteAssemblingSection(CAssemblingSection *pSection);
#ifdef _DEBUG
static void DumpAssemblingSectionList(void);
#endif


static BOOL GetBit(BYTE data, BYTE index)
{
	BOOL bBit = FALSE;

	BYTE match = 0x01<<(index-1);

	bBit = (data&match)>>(index-1);

	return bBit;
}

BOOL RegisterPSIPID(SHORT pid)
{
	BOOL bRet = FALSE;
	if(PSI_PID_count < MAX_PSI_PID)
	{
		PSI_PID[PSI_PID_count] = pid;
		PSI_PID_count++;
		bRet = TRUE;
	}

	return bRet;
}

static void PSIInit(void)
{
	memset(PSI_PID, 0x0, sizeof(PSI_PID));

	RegisterPSIPID(PID_PAT);
	RegisterPSIPID(PID_CAT);
	RegisterPSIPID(PID_TSDT);
	RegisterPSIPID(PID_NIT);
	RegisterPSIPID(PID_SDT);
	RegisterPSIPID(PID_EIT);
	RegisterPSIPID(PID_RST);
	RegisterPSIPID(PID_TOT);
}

BOOL IsPSIPID(SHORT pid)
{
	BOOL bRet = FALSE;
	int n = 0;
	for(n = 0; n < PSI_PID_count; n++)
	{
		if (pid == PSI_PID[n])
		{
			bRet = TRUE;
			break;
		}
	}
	return bRet;
}

void AssemblingTSP(CTSP* pTSP, CTSStatistic* pStatistic)
{
	CAssemblingSection *pNewSection = NULL;
	if(pTSP)
	{
		if(pTSP->IsStartIndicator() && pTSP->HavePayLoad()&& IsPSIPID(pTSP->GetPID()))
		{
			pNewSection = new CAssemblingSection();
			VERIFY(pNewSection);

			pNewSection->m_PID = pTSP->GetPID();
			InsertNewAssemblingSection(pNewSection);
		}
		else
		{
			pNewSection = FindAssemblingSection(pTSP);
		}

		if (pNewSection == NULL)
		{
			//not in the assembling section list
			return;
		}

		if(pNewSection->Payload(pTSP))
		{
			if(pNewSection->IsCompleted())
			{
				BOOL bSectionInsert = FALSE;
				if(pStatistic)
				{
					//one section is been assembled, Create one table;
					CPID* pPID = pStatistic->FindPID(pNewSection->m_PID);
					if (pPID)
					{
						CMpegTable* pTable = pPID->FindTable(pNewSection->m_table_id);
						if(pTable == NULL)
						{
							CMpegTable* pNewTable = NewTable(pNewSection);
							if(pNewTable)
							{
								bSectionInsert = pPID->AddTable(pNewTable);

								if(bSectionInsert)
								{
									pTable = pNewTable;									
									DWORD parameter, parameterEx;
									//Insert the Table Node
									parameter = (pNewSection->m_PID<<16)+(0xFF<<8)+pNewSection->m_table_id;
									CTreeNode* pTableNode = new CTreeNode(parameter, 0);
									::SendMessage(AfxGetMainWnd()->GetSafeHwnd(), WM_UPDATETREE, (WPARAM)pTableNode, 0);
									
									//Insert the section Node
									parameterEx = (pNewSection->m_parameter<<16)+(pNewSection->m_version<<8)+pNewSection->m_section_number;
									CTreeNode* pSectionNode = new CTreeNode(parameter, parameterEx);
									::SendMessage(AfxGetMainWnd()->GetSafeHwnd(), WM_UPDATETREE, (WPARAM)pSectionNode, 0);
								}
							}
							else
							{
								//unknown table
								//delete pNewSection;
							}
						}
						else
						{
							CSection* pSection = pTable->FindSection(pNewSection);
							if(pSection == NULL)
							{
								bSectionInsert = pTable->AddSection(pNewSection);
								if(bSectionInsert)
								{
									DWORD parameter, parameterEx;
									parameter = (pNewSection->m_PID<<16)+(0xFF<<8)+pNewSection->m_table_id;
									parameterEx = (pNewSection->m_parameter<<16)+(pNewSection->m_version<<8)+pNewSection->m_section_number;
									CTreeNode* pSectionNode = new CTreeNode(parameter, parameterEx);
									::SendMessage(AfxGetMainWnd()->GetSafeHwnd(), WM_UPDATETREE, (WPARAM)pSectionNode, 0);
								}

							}
							else
							{
								//delete pNewSection;
							}
						}

						if (pTable)
						{
							if(pTable->GetTableId() == TABLE_PAT && bSectionInsert)
							{
								pTable->Parser();
							}
						}
					}
					else
					{
						//error! cannot found PID
						//delete pNewSection;
					}
				}

				DeleteAssemblingSection(pNewSection);
				if(!bSectionInsert)
				{
					delete pNewSection;
				}
#ifdef _DEBUG
				//pStatistic->Dump();
#endif
			}
		}
		else
		{
			DeleteAssemblingSection(pNewSection);
			delete pNewSection;
		}
	}
#ifdef _DEBUG
	//DumpAssemblingSectionList();	
#endif
}

static CAssemblingSection* FindAssemblingSection(CTSP* pTSP)
{
	CAssemblingSection* pSection = NULL;
	if (pTSP && pHead)
	{
		AssemblingSectionNode* pNode = pHead;

		while(pNode)
		{
			if(pNode->pSection)
			{
				if (pNode->pSection->m_PID == pTSP->GetPID())
				{
					pSection = pNode->pSection;
					break;
				}
			}
			pNode = pNode->pNext;
		}
	}

	return pSection;
}

static BOOL InsertNewAssemblingSection(CAssemblingSection* pSection)
{
	BOOL bRet = FALSE;
	AssemblingSectionNode* pNode = pHead;
	AssemblingSectionNode* pInsertNode = new AssemblingSectionNode;

	ASSERT(pSection->m_PID != 0x1FFF);
	
	if(pInsertNode)
	{
		pInsertNode->pSection = pSection;
		pInsertNode->pNext = NULL;

		//Add to the head
		if(pNode == NULL)
		{
			pHead = pInsertNode;
		}
		else
		{
			pInsertNode->pNext = pHead;
			pHead = pInsertNode;
		}

		bRet = TRUE;
		LOG(LOG_INFO, _T("Start to assemble secion in PID 0x%04X"), pSection->m_PID);
	}
	
	return bRet;
}

static BOOL DeleteAssemblingSection(CAssemblingSection *pSection)
{
	BOOL bRet = FALSE;
	AssemblingSectionNode* pNode = pHead;
	AssemblingSectionNode* pDelete = NULL;

	while(pNode)
	{
		if(pNode->pSection == pSection)
		{			
			break;
		}

		pDelete = pNode;
		pNode = pNode->pNext;
	}

	if(pNode == pHead)
	{
		pHead = pNode->pNext;
	}
	else
	{
		pDelete->pNext = pNode->pNext;
	}

	if(pNode != NULL)
	{
		LOG(LOG_INFO, _T("Delete the assembling section in PID0x%04X, table id 0x%02X, sec num 0x%02X"),pSection->m_PID, pSection->m_table_id, pSection->m_section_number);

		delete pNode;
		pNode = NULL;
		bRet = TRUE;
	}

	return bRet;
}

#ifdef _DEBUG
static void DumpAssemblingSectionList(void)
{
	AssemblingSectionNode* pNode = pHead;
	TRACE(_T("-------------Start-----------------\n"));
	while(pNode)
	{
		CAssemblingSection* pSection = pNode->pSection;
		if(pSection)
		{
			TRACE(_T("Section: PID= 0x%04X, table_id 0x%02X\n"),pSection->m_PID, pSection->m_table_id);
		}
		pNode = pNode->pNext;
	}
	TRACE(_T("-------------End-----------------\n"));
}

#endif //_DEBUG

CMpegTable* NewTable(CSection* pSection)
{
	CMpegTable* pTable = NULL;

	if(pSection)
	{
		BYTE table_id = pSection->m_table_id;

		switch(table_id)
		{
		case TABLE_PAT:
			pTable = new CPAT();
			break;
		case TABLE_PMT:
			pTable = new CPMT();
			break;
		case TABLE_CAT:
			pTable = new CCAT();
			break;
		case TABLE_NIT_ACTUAL:
		case TABLE_NIT_OTHER:
			pTable = new CNIT();
			break;
		case TABLE_SDT_ACTUAL:
		case TABLE_SDT_OTHER:
			pTable = new CSDT();
			break;
		case TABLE_BAT:
			pTable = new CBAT();
			break;
		//TODO: add new case, to handle different table
		default:
			if(table_id >= 0x4E && table_id <= 0x6F)
			{
				pTable = new CEIT();
			}
			else
			{
				TRACE(_T("Unknown Table(table id 0x%02X)!\n"), table_id);
			}
			break;
		}
	}

	if(pTable)
	{
		pTable->AddSection(pSection);
	}

	return pTable;
}


void MpegParserInit(void)
{
	PSIInit();
}

void MpegParserTerm(void)
{
	if(pHead)
	{
		AssemblingSectionNode* pNode = pHead;
		while(pNode)
		{
			AssemblingSectionNode* pRelease = pNode;
			pNode = pNode->pNext;

			delete pRelease->pSection;
			pRelease->pSection = NULL;
			delete pRelease;
		}
	}
}

CTSP::CTSP(void)
{
	m_szbuf = NULL;
	m_type = TS_UNKNOWN;
	m_bValid = TRUE;
	m_PID = 0x1FFF;
	m_pAdaptionField = NULL;
	m_AdaptionFieldLen = 0;
	m_pPayload = NULL;
	m_PayloadLen = 0;
}

CTSP::CTSP(TS_Type type)
{
	m_szbuf = NULL;
	m_type = TS_UNKNOWN;
	m_bValid = TRUE;
	m_PID = 0x1FFF;
	m_pAdaptionField = NULL;
	m_AdaptionFieldLen = 0;
	m_pPayload = NULL;
	m_PayloadLen = 0;

	if(type == TS_188 || type == TS_204)
	{
		m_szbuf = (BYTE*)malloc(type);
		m_type = type;
	}
}

CTSP::CTSP(TS_Type type, BYTE* szData)
{
	m_szbuf = NULL;
	m_type = TS_UNKNOWN;
	m_bValid = TRUE;
	m_PID = 0x1FFF;
	m_pAdaptionField = NULL;
	m_AdaptionFieldLen = 0;
	m_pPayload = NULL;
	m_bPayload = FALSE;
	m_PayloadLen = 0;

	if((type == TS_188 || type == TS_204) && szData)
	{		
		if(m_szbuf == NULL && szData != NULL && szData[0] == 0x47)
		{
			m_szbuf = (BYTE*)malloc(type);
			memcpy(m_szbuf, szData, type);
			m_type = type;
		}
	}

	BYTE transport_error_indicator, payload_unit_start_indicator, transport_priority;
	BYTE transport_scambling_control, adaption_field_control, continuty_counter;
	SHORT PID;

	transport_error_indicator = GetBit(szData[1], 8);
	payload_unit_start_indicator = GetBit(szData[1], 7);
	transport_priority = GetBit(szData[1], 6);
	PID = ((szData[1]&0x1F)<<8) + szData[2];
	transport_scambling_control = (szData[3]&0xC0)>>6;
	adaption_field_control = (szData[3]&0x30)>>4;
	continuty_counter = szData[3]&0xF;

	m_PID = PID;
	//NULL Packet
	if(PID == 0x1FFF)
	{
		return;
	}

	m_bStartIndicator = payload_unit_start_indicator;

	if (transport_error_indicator && szData[0]!=0x47)
	{
		m_bValid = FALSE;
		LOG(LOG_ERROR, _T("This TS packet in PID 0x%04X is error, need to be skiped!"));
	}

	if(PID == 0x1FFF && (payload_unit_start_indicator != 0||adaption_field_control != 1))
	{
		m_bValid = FALSE;
		LOG(LOG_ERROR, _T("The payload_unit_start_indicator should be 0 or adaption_field_control should be 1 in the NULL packet"));
	}

	if(adaption_field_control == 0x02 || adaption_field_control == 0x03)
	{
		m_pAdaptionField = szData + 5;
		m_AdaptionFieldLen = szData[4];
	}

	if(adaption_field_control == 0x01 || adaption_field_control == 0x03)
	{
		m_bPayload = TRUE;
		if(payload_unit_start_indicator == 1)
		{
			BYTE pointer_field = 0;
			if(m_pAdaptionField)
			{
				pointer_field = szData[5+m_AdaptionFieldLen];
				m_pPayload = szData + 6 + m_AdaptionFieldLen + pointer_field;
				m_PayloadLen = 182 - m_AdaptionFieldLen - pointer_field;
			}
			else
			{
				pointer_field = szData[4];
				m_pPayload = szData + 5 + pointer_field;
				m_PayloadLen = 183 - pointer_field;
			}
		}
		else
		{
			if(m_pAdaptionField)
			{
				m_pPayload = szData + 5 + m_AdaptionFieldLen;
				m_PayloadLen = 183 - m_AdaptionFieldLen;
			}
			else
			{
				m_pPayload = szData + 4;
				m_PayloadLen = 184;
			}
		}		
	}
}

CTSP::~CTSP(void)
{
	if(m_szbuf)
	{
		//free the malloc buffer
		free(m_szbuf);
	}
}

BOOL CTSP::IsValid(void)
{
	return m_bValid;
}

BYTE CTSP::IsStartIndicator(void)
{
	return m_bStartIndicator;
}

SHORT CTSP::GetPID(void)
{
	return m_PID;
}

BOOL CTSP::HavePayLoad(void)
{
	return m_bPayload;
}

BOOL CTSP::GetPayLoad(BYTE** pPayload, BYTE* pLen)
{
	BOOL bRet = FALSE;

	if(m_bPayload)
	{
		if(pPayload && *pPayload && pLen)
		{
			*pPayload = m_pPayload;
			*pLen = m_PayloadLen;
			bRet = TRUE;
		}
	}

	return bRet;
}




CSection::CSection(void)
{
	m_szData = NULL;
	m_table_id = 0xFF;
	m_parameter = 0;
	m_section_number = 0xFF;
	m_version = 0xFF;
	m_PID = 0x1FFF;
	m_section_length = 0;
	m_pNext = NULL;

	m_szData = new BYTE[MAX_SECTION_LEN];
	VERIFY(m_szData);
}

CSection::~CSection(void)
{
	if(m_szData)
	{
		delete [] m_szData;
		m_szData = NULL;
	}
	m_pNext = NULL;
}

CAssemblingSection::CAssemblingSection(void)
{
	m_CopyPosition = 0;
	m_bComplete = FALSE;
}

CAssemblingSection::~CAssemblingSection(void)
{
	
}

CAssemblingSection::CAssemblingSection(CTSP* pTSP)
{
	m_CopyPosition = 0;
	m_bComplete = FALSE;
	m_PID = pTSP->GetPID();

	if(pTSP)
	{
		BYTE* pPayload;
		BYTE PayloadLen;
		pTSP->GetPayLoad(&pPayload, &PayloadLen);

		if(pPayload && PayloadLen > 0)
		{
			memcpy(m_szData, pPayload, PayloadLen);
			m_CopyPosition += PayloadLen;
		}
	}
}

void CAssemblingSection::Format(void)
{
	if(m_szData && m_CopyPosition > 7)
	{
		m_table_id = m_szData[0];
		m_section_length = ((m_szData[1]&0x0F)<<8) + m_szData[2];
		m_parameter = (m_szData[3]<<8)+m_szData[4];
		m_version = (m_szData[5]&0x3E)>>1;
		m_section_number = m_szData[6];
	}
}

BOOL CAssemblingSection::Payload(CTSP* pTSP)
{
	BOOL bRet = FALSE;
	if(pTSP)
	{
		BYTE* pPayload;
		BYTE PayloadLen;
		if (pTSP->GetPayLoad(&pPayload, &PayloadLen))
		{
			if(pPayload && PayloadLen > 0)
			{
				BYTE copylen = (m_CopyPosition+PayloadLen <= 4096)? PayloadLen:(4096-m_CopyPosition);
				memcpy(m_szData + m_CopyPosition, pPayload, PayloadLen);		
				m_CopyPosition += copylen;

				if(m_CopyPosition > 7 && m_CopyPosition - PayloadLen < 7)
				{
					m_PID = pTSP->GetPID();
					Format();				
				}
				bRet = TRUE;



				if(m_CopyPosition >= (m_section_length + 3) && m_CopyPosition != 0)
				{
					m_bComplete = TRUE;
					LOG(LOG_INFO, _T("The section(PID 0x%04X, table id0x%02X sec num 0x%02X) is assembled completed"), m_PID, m_table_id, m_section_number);
					//CRC32 check here, otherwise return 'false'
				}
			}
		}
	}

	return bRet;
}

BOOL CAssemblingSection::IsCompleted(void)
{
	return m_bComplete;
}


CMpegTable::CMpegTable(void)
{
	m_pSectionHead = NULL;
	m_pNext = NULL;
}

CMpegTable::~CMpegTable(void)
{
}

BOOL CMpegTable::AddSection(CSection* pAddSection)
{
	BOOL bRet = FALSE;
	CSection* pSection = m_pSectionHead;
	CSection* pInsertSection = NULL;

	if(pAddSection == NULL)
	{
		return bRet;
	}

	if(pSection == NULL)
	{
		m_pSectionHead = pAddSection;
		pAddSection->m_pNext = NULL;
	}
	else
	{
		while(pSection)
		{			
			if(pSection->m_parameter >= pAddSection->m_parameter)
			{
				if((pSection->m_parameter == pAddSection->m_parameter && pSection->m_section_number > pAddSection->m_section_number) \
					|| (pSection->m_parameter > pAddSection->m_parameter))
				{
					break;
				}
			}	
			pInsertSection = pSection;
			pSection = pSection->m_pNext;
		}

		if(pSection == NULL)
		{
			pInsertSection->m_pNext = pAddSection;
			pAddSection->m_pNext = NULL;
		}

		if(pSection == m_pSectionHead)
		{
			pAddSection->m_pNext = m_pSectionHead;
			m_pSectionHead = pAddSection;
		}
		else
		{
			pAddSection->m_pNext = pSection;
			pInsertSection->m_pNext = pAddSection;
		}
}
	bRet = TRUE;
	LOG(LOG_INFO, _T("Table(table id 0x%02X):add one section sec_num(0x%02X)"),pAddSection->m_table_id, pAddSection->m_section_number);
	TRACE(_T("Table(table id 0x%02X):add one section sec_num(0x%02X)\n"),pAddSection->m_table_id, pAddSection->m_section_number);

	return bRet;
}

BYTE CMpegTable::GetTableId(void)
{
	BYTE table_id = 0xFF;
	CSection* pSection = m_pSectionHead;
	
	if (pSection)
	{
		table_id = pSection->m_table_id;
	}
	return table_id;
}

CSection* CMpegTable::FindSection(CSection* pFindSection)
{
	CSection* pSection = NULL;
	CSection* pNode = m_pSectionHead;

	while(pNode)
	{
		if(pNode->m_section_number == pFindSection->m_section_number \
			&& pNode->m_version == pFindSection->m_version \
			&& pNode->m_parameter == pFindSection->m_parameter)
		{
			pSection = pNode;
			break;
		}
		pNode = pNode->m_pNext;
	}

	return pSection;
}

CSection* CMpegTable::FindSection(USHORT parameter, BYTE version, BYTE section_number)
{
	CSection* pSection = NULL;
	CSection* pNode = m_pSectionHead;

	while(pNode)
	{
		if(pNode->m_section_number == section_number \
			&& pNode->m_version == version \
			&& pNode->m_parameter == parameter)
		{
			pSection = pNode;
			break;
		}
		pNode = pNode->m_pNext;
	}

	return pSection;
}



CPAT::CPAT(void)
{
}

CPAT::~CPAT(void)
{
}

BOOL CPAT::Parser(void)
{
	BOOL bRet = FALSE;

	if(m_pSectionHead)
	{
		TRACE(_T("Parse PAT!\n"));
		CSection* pNode = m_pSectionHead;
		while(pNode)
		{
			bRet = Parser(pNode);
			pNode = pNode->m_pNext;
		}
	}

	return bRet;
}

BOOL CPAT::Parser(CSection* pSection)
{
	BOOL bRet = FALSE;
	if(pSection)
	{
		BYTE* pBuf = pSection->m_szData;
		USHORT section_length = pSection->m_section_length;
		USHORT pos = 8;
		section_length -= 9;
		while(section_length > 0)
		{
			USHORT program_number, program_map_PID;
			program_number = (pBuf[pos]<<8) + pBuf[pos+1];
			program_map_PID = ((pBuf[pos+2]&0x1F)<<8) + pBuf[pos+3];
			if(program_number!= 0)
			{
				RegisterPSIPID(program_map_PID);
			}

			pos += 4;
			section_length -= 4;
		}
		bRet = TRUE;
	}

	return bRet;
}

CCAT::CCAT(void)
{
}

CCAT::~CCAT(void)
{
}

BOOL CCAT::Parser(void)
{
	return TRUE;
}

CPMT::CPMT(void)
{
}

CPMT::~CPMT(void)
{
}

BOOL CPMT::Parser(void)
{
	return TRUE;
}

CNIT::CNIT(void)
{
}

CNIT::~CNIT(void)
{
}

BOOL CNIT::Parser(void)
{
	return TRUE;
}

CBAT::CBAT(void)
{
}

CBAT::~CBAT(void)
{
}

BOOL CBAT::Parser(void)
{
	return TRUE;
}

CSDT::CSDT(void)
{
}

CSDT::~CSDT(void)
{
}

BOOL CSDT::Parser(void)
{
	return TRUE;
}

CEIT::CEIT(void)
{
	m_network_id = 0;
	m_transport_stream_id = 0;
	m_service_id = 0;
}

CEIT::~CEIT(void)
{
}

BOOL CEIT::Parser(void)
{
	return TRUE;
}



////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////

CPID::CPID(void)
{
	m_PID = 0x1FFF;
	m_pNext = NULL;
	m_pTableHead = NULL;
}

CPID::~CPID(void)
{
}

CPID::CPID(SHORT PID)
{
	m_pNext = NULL;
	m_PID = PID;
	m_pTableHead = NULL;
}

SHORT CPID::GetPID(void)
{
	return m_PID;
}

CPID* CPID::GetNext(void)
{
	return m_pNext;
}

void CPID::Attach(CPID* hpid)
{
	m_pNext = hpid;
}

BOOL CPID::AddTable(CMpegTable* pAddTable)
{
	BOOL bRet = FALSE;
	CMpegTable* pTable = m_pTableHead;
	CMpegTable* pInsertTable = NULL;

	if (pAddTable == NULL)
	{
		return bRet;
	}

	//First table
	if(pTable == NULL)
	{
		m_pTableHead = pAddTable;
		pAddTable->m_pNext = NULL;
	}
	else
	{
		while(pTable)
		{
			if(pTable->GetTableId() > pAddTable->GetTableId())
			{
				if(pTable == m_pTableHead)
				{
					pAddTable->m_pNext = pTable;
					m_pTableHead = pAddTable;
				}
				else
				{
					pAddTable->m_pNext = pTable;
					pInsertTable->m_pNext = pAddTable;
				}
				break;
			}
			pInsertTable = pTable;
			pTable = pTable->m_pNext;
		}

		if(pTable == NULL)
		{
			pInsertTable->m_pNext = pAddTable;
			pAddTable->m_pNext = NULL;
		}
	}
	bRet = TRUE;
	LOG(LOG_INFO, _T("PID(pid 0x%04X):add one table(table id 0x%02X)"),m_PID, pAddTable->GetTableId());
	TRACE(_T("PID(pid 0x%04X):add one table(table id 0x%02X)\n"),m_PID, pAddTable->GetTableId());

	return bRet;
}

CMpegTable* CPID::FindTable(BYTE table_id)
{
	CMpegTable* pTable = NULL;
	CMpegTable* pNode = m_pTableHead;

	while(pNode)
	{
		if(pNode->GetTableId() == table_id)
		{
			pTable = pNode;
			break;
		}
		pNode = pNode->m_pNext;
	}

	return pTable;
}


////////////////////////////////////////////////////////////////////////////////////
/*


*/
////////////////////////////////////////////////////////////////////////////////////

CTSStatistic::CTSStatistic(void)
{
	m_hPIDNodeHead = NULL;
}

CTSStatistic::~CTSStatistic(void)
{
	if (m_hPIDNodeHead)
	{
		CPID* pNode = m_hPIDNodeHead;
		while(pNode)
		{
			CPID* pRelease = pNode;
			CMpegTable* pTableNode = pNode->m_pTableHead;
			while(pTableNode)
			{
				CSection* pSecNode = pTableNode->m_pSectionHead;
				while(pSecNode)
				{
					CSection* pRelease = pSecNode;
					pSecNode = pSecNode->m_pNext;
					delete pRelease;
				}
				CMpegTable* pReleaseTable = pTableNode;
				pTableNode = pTableNode->m_pNext;
				delete pReleaseTable;
			}
			pNode = pNode->GetNext();
			delete pRelease;
		}
	}
	m_hPIDNodeHead = NULL;
}

BOOL CTSStatistic::InsertPID(CPID* hpid)
{
	BOOL bRet = FALSE;

	if(hpid)
	{
		CPID* pInsert = NULL;
		if (!m_hPIDNodeHead)
		{
			//head
			m_hPIDNodeHead = hpid;
		}
		else
		{
			CPID* pNode = m_hPIDNodeHead;
			while(pNode)
			{				
				if(pNode->GetPID() > hpid->GetPID())
				{
					break;
				}
				pInsert = pNode;
				pNode = pNode->GetNext();
			}
			
			//insert to the tail
			if(pNode == NULL)
			{
				pInsert->Attach(hpid);
			}

			if(pNode == m_hPIDNodeHead)
			{
				hpid->Attach(m_hPIDNodeHead);
				m_hPIDNodeHead = hpid;
			}
			else
			{
				hpid->Attach(pNode);
				pInsert->Attach(hpid);
			}

		}

		bRet = TRUE;
		LOG(LOG_INFO, _T("Find new PID(0x%04X) in the TS"),hpid->GetPID());
	}

	return bRet;
}

CPID* CTSStatistic::FindPID(SHORT pid)
{
	CPID* pPID = NULL;
	CPID* pNode = m_hPIDNodeHead;

	while(pNode)
	{
		if(pNode->GetPID() == pid)
		{
			pPID = pNode;
			break;
		}

		pNode = pNode->GetNext();
	}

	return pPID;
}

#ifdef _DEBUG
void CTSStatistic::Dump(void)
{
	TRACE(_T("-----------------TS Statistic----------------------\n"));
	CPID* pPIDNode = m_hPIDNodeHead;

	while(pPIDNode)
	{
		TRACE(_T("PID(0x%04X)\n"), pPIDNode->GetPID());
		CMpegTable* pTableNode = pPIDNode->m_pTableHead;
		while(pTableNode)
		{
			TRACE(_T("PID(0x%04X):Table 0x%02X\n"), pPIDNode->GetPID(), pTableNode->GetTableId());
			CSection* pSecNode = pTableNode->m_pSectionHead;
			while(pSecNode)
			{
				TRACE(_T("Table(0x%02X):parameter 0x%04X Section 0x%02X\n"),pTableNode->GetTableId(),pSecNode->m_parameter, pSecNode->m_section_number);
				pSecNode = pSecNode->m_pNext;
			}
			pTableNode = pTableNode->m_pNext;
		}
		pPIDNode = pPIDNode->GetNext();
	}
	TRACE(_T("---------------/*TS Statistic*/--------------------\n"));
}
#endif

CTSGConfig::CTSGConfig(void)
{
	m_type = TS_UNKNOWN;
}

CTSGConfig::~CTSGConfig(void)
{
}

void CTSGConfig::SetType(TS_Type type)
{
	m_type = type;
}

TS_Type CTSGConfig::GetType(void)
{
	return m_type;
}

void CTSGConfig::SetOffset(SHORT offset)
{
	m_offset = offset;
}

SHORT CTSGConfig::GetOffset(void)
{
	return m_offset;
}

// save the config to the disk
BOOL CTSGConfig::SaveConfig(void)
{
	BOOL bRet = FALSE;

	CFile FileConfig;
	CFileException e;

	TCHAR dir[64];
	GetCurrentDirectory(64, dir);
	CString Path(dir);
	Path += "\\TSG.cfg";
	
	if( FileConfig.Open(Path, CFile::modeWrite|CFile::modeCreate, &e))
	{
		CHAR output[64] = "";
		sprintf_s(output,"[TS_TYPE]%d\n",m_type);
		FileConfig.Write(output, strlen(output));

		sprintf_s(output,"[TS_OFFSET]%d\n",m_offset);
		FileConfig.Write(output, strlen(output));
	}

	FileConfig.Flush();
	FileConfig.Close();

	return bRet;
}

